﻿using System;
using System.Web.Mvc;
using System.ComponentModel;
using Inovout.Models;
using System.Linq;
using System.Globalization;
using Inovout.Services;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.Collections;

namespace Inovout.Web.Binders
{
    public class EntityModelBinder : DefaultModelBinder
    {
        private static readonly string idKey = "Id";

        protected override object CreateModel(ControllerContext controllerContext,
            ModelBindingContext bindingContext, Type modelType)
        {
            if (typeof(DataObject).IsAssignableFrom(modelType))
            {
                var idValueProviderResult = bindingContext.ValueProvider.GetValue(idKey);
                if (idValueProviderResult != null)
                {
                    IRepositoryService repositoryService = GetRepositoryService(modelType);
                    return repositoryService.FindById(idValueProviderResult.RawValue);
                 }
            }
            if (modelType.IsInterface)
            {
                return ComponentRegistry.Resolve(modelType);
            }
            return base.CreateModel(controllerContext, bindingContext, modelType);

        }

        protected virtual IRepositoryService GetRepositoryService(Type modelType)
        {
            Type respositoryServiceType = typeof(IRepositoryService<>);
            respositoryServiceType = respositoryServiceType.MakeGenericType(modelType);
            return ComponentRegistry.Resolve<IRepositoryService>(respositoryServiceType);
        }

        protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
        {
            string fullPropertyKey = CreateSubPropertyName(bindingContext.ModelName, propertyDescriptor.Name);
            if (bindingContext.ValueProvider.ContainsPrefix(fullPropertyKey))
            {
                ValueProviderResult vpResult = bindingContext.ValueProvider.GetValue(fullPropertyKey);
                TypeConverter converter = TypeDescriptor.GetConverter(propertyDescriptor.PropertyType);
                //值不为空！
                //排除Oject类型
                //因为Json是不能直接转换为复杂类型
                if (vpResult != null && !propertyDescriptor.PropertyType.Equals(typeof(object)) && !converter.CanConvertFrom(typeof(string)))
                {
                    //判断是否为JSON逻辑仍不精度，最好能通过正则表达式来验证。
                    string jsonString = (string)vpResult.AttemptedValue;
                    jsonString = jsonString.Trim();
                    Dictionary<string, string> jsonModelPropertyDictionary = new Dictionary<string, string>();
                    if (jsonString.StartsWith("{") && jsonString.EndsWith("}"))
                    {
                        Dictionary<string, string> jsonDictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonString);
                        foreach (var dicEntiry in jsonDictionary)
                        {
                            jsonModelPropertyDictionary.Add(string.Format("{0}.{1}", propertyDescriptor.Name, dicEntiry.Key), dicEntiry.Value);
                        }

                    }
                    else
                    {
                        List<Dictionary<string, string>> jsonCollectionDictionaryList = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(jsonString);

                        for (int i = 0; i < jsonCollectionDictionaryList.Count; i++)
                        {
                            string prefix = string.Format("{0}[{1}]", propertyDescriptor.Name, i.ToString());
                            foreach (var dicEntiry in jsonCollectionDictionaryList[i])
                            {
                                jsonModelPropertyDictionary.Add(string.Format("{0}.{1}", prefix, dicEntiry.Key), dicEntiry.Value);
                            }
                        }
                    }
                    bindingContext = new ModelBindingContext()
                    {
                        ModelMetadata = bindingContext.ModelMetadata
,
                        ModelState = bindingContext.ModelState,
                        ValueProvider = new DictionaryValueProvider<string>(jsonModelPropertyDictionary, CultureInfo.CurrentCulture)
                    };
                }
                base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
            }
        }

    }
}

